home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo1.zoo / demo / icon / zoom.c < prev   
Encoding:
C/C++ Source or Header  |  1989-01-24  |  28.3 KB  |  1,023 lines

  1. /*                        Copyright (c) 1988 Bellcore
  2.  *                            All Rights Reserved
  3.  *       Permission is granted to copy or use this program, EXCEPT that it
  4.  *       may not be sold for profit, the copyright notice must be reproduced
  5.  *       on copies, and credit should be given to Bellcore where it is due.
  6.  *       BELLCORE MAKES NO WARRANTY AND ACCEPTS NO LIABILITY FOR THIS PROGRAM.
  7.  */
  8. /*    $Header: zoom.c,v 4.4 88/07/11 13:10:39 sau Exp $
  9.     $Source: /tmp/mgrsrc/demo/icon/RCS/zoom.c,v $
  10. */
  11. static char    RCSid_[] = "$Source: /tmp/mgrsrc/demo/icon/RCS/zoom.c,v $$Revision: 4.4 $";
  12.  
  13. /* icon edittor -- version I (single window) */
  14.  
  15. #include <stdio.h>
  16. #include <signal.h>
  17. #include <sys/file.h>
  18. #include "term.h"
  19. #include "bitmap.h"
  20.  
  21. /* general defines */
  22.  
  23. #define GAP    2        /* general purpose gap */
  24. #define TITLE    20        /* cols needed for title */
  25. #define MAXMARK    7        /* max # of text items on status line */
  26. #define MIN    4        /* min number of pixels in a bitmap */
  27. #define SLEEP    5        /* time it takes for a message to go away */
  28. #define SETMSG    1        /* set the message */
  29. #define MAX    100        /* max # of pixels in a bitmap */
  30. #define FILES    100        /* max # of files to edit at once */
  31.  
  32. /* bitmap functions */
  33.  
  34. #define SET    0        /* bit set */
  35. #define CLEAR    1        /* clear */
  36. #define TOGGLE    2        /* toggle */
  37. #define ON    4        /* bit is on */
  38. #define OFF    0        /* bit is off */
  39.  
  40. /* zoom options */
  41.  
  42. #define YANK    1        /* yank a region */
  43. #define PUT    2        /* put a previously yanked region */
  44. #define SHRINK    3        /* make icon smaller */
  45. #define GROW    4        /* make icon bigger */
  46. #define SHIFT    5
  47.  
  48. /* title fields */
  49.  
  50. #define T_FUNC    0        /* raster op functions */
  51. #define T_OP    1        /* sweep otions */
  52. #define T_SIZE    2        /* bitmap size */
  53. #define T_NAME    3        /* file name */
  54.  
  55. /* menu names */
  56.  
  57. #define M_MODES        1    /* set/clear/toggle */
  58. #define M_OPTIONS    2    /* yank/put/shrink/grow/ */
  59. #define M_SIZE        3    /* none */
  60. #define M_EDIT        4    /* save/get */
  61. #define M_PUT        5    /* put functions */
  62. #define M_FILES        6    /* name of files to edit */
  63.  
  64. #define dprintf    if(debug)fprintf
  65.  
  66. #define SET_FUNC(n) \
  67.     (n!=func ? m_func(func = n) : n);
  68. #define SWAP(x,y) \
  69.     (code=x,x=y,y=code)
  70. #define MARK(i) \
  71.     ((i)>=0 ? marks[i] : 0)
  72.  
  73. #ifndef Min
  74. #define Min(x,y)    ((x)<(y)?(x):(y))
  75. #endif
  76. #ifndef Max
  77. #define Max(x,y)    ((x)>(y)?(x):(y))
  78. #endif
  79.  
  80. #define INVERT(i) \
  81.     m_bitwrite(x0+MARK(i-1),0,MARK(i)-MARK(i-1),font_high);
  82.  
  83. #define W    BIT_WIDE
  84. #define H    BIT_HIGH
  85.  
  86. /* menus */
  87.  
  88. struct menu_entry modes[] = {
  89.    "set", "s0\r",
  90.    "clear","s1\r",
  91.    "toggle","s2\r",
  92.    "grid","x\r",
  93.    };
  94.  
  95. struct menu_entry edit[] = {
  96.    "save","f\r",
  97.    "get","g\r",
  98.    "yank","y\r",
  99.    "quit","Q\r"
  100.    };
  101.  
  102. struct menu_entry resize[] = {
  103.    "resize","+\r",
  104.    };
  105.  
  106. struct menu_entry options[] = {
  107.    "yank","F1\r",
  108.    "put","F2\r",
  109.    "shrink","F3\r",
  110.    "grow","F4\r",
  111.    "shift","F5\r",
  112.    "fix window","w\r",
  113.    "undo","u\r",
  114.    };
  115.  
  116. struct menu_entry functions[] = {
  117.    "copy","P0\r",
  118.    "paint","P1\r",
  119.    "mask","P2\r",
  120.    "xor","P3\r",
  121.    "grid","x\r",
  122.    };
  123.  
  124. struct menu_entry sizes[] = {
  125.    "normal cursor","16,16",
  126.    "small icon","48,48",
  127.    "normal icon","64,64",
  128.    };
  129.  
  130. struct menu_entry files[FILES];
  131.  
  132. char name[80];                /* name of icon */
  133.  
  134. /* function codings for put */
  135.  
  136. int func_put[] = {
  137.    BIT_SRC, BIT_SRC|BIT_DST, BIT_SRC&BIT_DST, BIT_SRC^BIT_DST
  138.    };
  139.  
  140. int func_zoom[] = {
  141.    BIT_SRC^BIT_DST, BIT_SRC&BIT_NOT(BIT_DST), BIT_DST&BIT_NOT(BIT_SRC), BIT_SRC
  142.    };
  143.    
  144.  
  145. int marks[MAXMARK];        /* positions demarcating labels */
  146. int win_wide, win_high;        /* window size */
  147. int win_x, win_y;        /* window location */
  148. int font_wide, font_high;    /* font size */
  149. int x0,y0;            /* starting location of icon*/
  150. int func;            /* current mgr raster function */
  151. int debug=0;
  152. char *title[MAXMARK];        /* title goes here */
  153. int xmax,ymax,border;        /* screen parameters */
  154. char *str_save(), *sprintf();
  155. char *prog;
  156.  
  157. main(argc,argv)
  158. int argc;
  159. char **argv;
  160.    {
  161.  
  162.    register int i, c;
  163.    int w, h;            /* bitmap size */
  164.    int x,y;            /* scale factors */
  165.    int mx,my;            /* mouse position */
  166.    int bitx, bity;        /* bit position in bitmap */
  167.    int lastx, lasty;        /* prev. bit position in bitmap */
  168.    int size;            /* size of bitmap (bytes) */
  169.    int done=0;            /* exit flag */
  170.    int code;            /* return codes */
  171.    int state;            /* bit toggle state */
  172.  
  173.    /* state flags */
  174.  
  175.    int menu = -1;        /* current menu selected */
  176.    int grid = 0;        /* grid state */
  177.    int mode = TOGGLE;        /* edit mode */
  178.    int function = 0;        /* function flag */
  179.    int put = 0;            /* put mode */
  180.  
  181.    /* misc */
  182.  
  183.    int file_count;        /* number of files in file menu */
  184.    char *pntr;            /* temp char pntr */
  185.    char dims[12];        /* string buffer for icon dims */
  186.    char line[512];        /* input buffer */
  187.  
  188.    char *sprintf(), *malloc(), *rindex(), *get_str(), *strcpy();
  189.    int clean(), message();
  190.  
  191.    BITMAP *map;                /* what your editting */
  192.    BITMAP *new, *temp;            /* temp bitmap */
  193.    BITMAP *yanked=BIT_NULL;        /* yanked bitmap */
  194.    BITMAP *last=BIT_NULL;        /* bitmap to undo */
  195.    BITMAP *read_icon(), *set_undo();
  196.  
  197.    ckmgrterm( *argv );
  198.    debug = getenv("DEBUG");
  199.  
  200.    if (argc <2) {
  201.       fprintf(stderr,"Usage: %s files...\n",argv[0]);
  202.       exit(1);
  203.       }
  204.    prog = *argv;
  205.  
  206.    /* setup mgr */
  207.  
  208.    m_setup(M_MODEOK);
  209.    m_ttyset();
  210.    m_push(P_FLAGS|P_MENU|P_EVENT);
  211.  
  212.    signal(SIGINT,clean);
  213.    signal(SIGTERM,clean);
  214.    signal(SIGALRM,message);
  215.  
  216.    m_setmode(M_ABS);
  217.    m_setmode(M_NOWRAP);
  218.    SET_FUNC(B_INVERT);
  219.    get_font(&font_wide, &font_high);
  220.    get_size(&win_x,&win_y,&win_wide,&win_high);
  221.    get_param(0,&xmax,&ymax,&border);
  222.  
  223.    menu_load(1,MENU_SIZE(modes),modes);
  224.    menu_load(2,MENU_SIZE(options),options);
  225.    menu_load(3,MENU_SIZE(resize),resize);
  226.    menu_load(4,MENU_SIZE(edit),edit);
  227.    menu_load(5,MENU_SIZE(functions),functions);
  228.  
  229.    for(i=1;i<argc && i<= FILES-3;i++) {        /* save room for new names */
  230.       pntr = rindex(argv[i],'/');
  231.       pntr = pntr ? pntr++ : argv[i];
  232.       files[i-1].value = str_save(pntr,"");
  233.       files[i-1].action = str_save(argv[i],"\r");
  234.       }
  235.    file_count = i-1;
  236.  
  237.    m_nomenu();
  238.  
  239.    /* get mgr events */
  240.  
  241.    m_setevent(BUTTON_1,"(%r)\r");
  242.    m_setevent(BUTTON_2,"[%p]\r");
  243.    m_setevent(BUTTON_2U,"$\r");
  244.    m_setevent(RESHAPED,"S\r");
  245.    m_setevent(REDRAW,"R\r");
  246.    m_setevent(MOVE,"M\r");
  247.    
  248.    /* read in icon */ 
  249.  
  250.    strcpy(name,argv[1]);
  251.    if ((map = read_icon(argv[1],0))  == BIT_NULL) {
  252.       pntr=get_str("Enter icon size (xxx,yyy):\n",
  253.             win_wide/2,win_high/2,sizes,MENU_SIZE(sizes));
  254.       sscanf(pntr,"%d,%d",&w,&h);
  255.       if (w>MAX || h>MAX || w<MIN || h<MIN) {
  256.          fprintf(stderr,"%s: Wrong size, try again\n",prog);
  257.          clean(1);
  258.          }
  259.       map = bit_alloc(w,h,BIT_NULL,1);
  260.       bit_blit(map,0,0,w,h,BIT_CLR,0,0,0);
  261.       }
  262.  
  263.    /* setup & display icon */
  264.     
  265.    x0 = 0;
  266.    y0 = font_high + 2*GAP;
  267.    get_scale(&x,&y,map);
  268.  
  269.    m_clear();
  270.    title[T_FUNC] = modes[mode].value;
  271.    title[T_OP] = options[function].value;
  272.    title[T_SIZE] = sprintf(dims,"%d x %d",W(map),H(map));
  273.    title[T_NAME] = name;
  274.    title[4] = NULL;
  275.    Do_title(title);
  276.  
  277.    zoom(map,x0,y0,x,y,SET);
  278.  
  279.    /* process menu and mouse hits */
  280.  
  281.    m_flush();
  282.    while (!done && m_gets(line) != NULL) {
  283.      dprintf(stderr,"main loop got: %s",line);
  284.      menu = -1;
  285.      m_nomenu();
  286.      switch(c = *line) {
  287.         case '[':                /* got button 1 hit */
  288.            sscanf(line+1,"%d %d]",&mx,&my);
  289.            dprintf(stderr,"Got %d,%d\n",mx,my);
  290.  
  291.            menu = -1;
  292.            if (my < y0) {            /* button 1 hit on menu */
  293.               for(i=0;i<4;i++)
  294.                   if (mx<marks[i]) {
  295.                      menu = i+1;
  296.                      break;
  297.                      }
  298.               }
  299.  
  300.            else {
  301.               lastx = -1;
  302.               last = set_undo(last,map);
  303.               while (*line != '$') {        /* button 1 hit on bitmap */
  304.                  bitx = (mx-GAP)/x;
  305.                  bity = (my-2*GAP-font_high)/y;
  306.                  dprintf(stderr,"read (%d/%d,%d/%d) was (%d,%d) %s",
  307.                          bitx,W(map),bity,H(map),lastx,lasty,line);
  308.  
  309.                  if (lastx == -1)  {
  310.                     mode = bit_on(map,bitx,bity) ? CLEAR : SET;
  311.                     title[T_FUNC]=modes[mode].value;
  312.                     Do_title(title);
  313.                     }
  314.    
  315.                  if (bitx==lastx && bity == lasty) {
  316.                     dprintf(stderr,"same bit %d,%d\n",bitx,bity);
  317.                     }
  318.                  else if (bitx < W(map) && bity < H(map)) {
  319.                     do_bit(map,x,y,bitx,bity,mode);
  320.                     }
  321.                  else {
  322.                     dprintf(stderr,"? bit %d,%d\n",bitx,bity);
  323.                     }
  324.  
  325.                  lastx=bitx; lasty=bity;
  326.                  m_getinfo(G_MOUSE2);
  327.                  m_flush();
  328.                  m_gets(line);
  329.                  sscanf(line,"%d %d",&mx,&my);
  330.                  if (debug) sleep(1);
  331.                  }
  332.               }
  333.  
  334.            /* set menu (if any) */
  335.  
  336.            if (menu>0) {
  337.               dprintf(stderr,"selecting menu %d ->",menu); fflush(stderr);
  338.               if (menu==M_MODES && function==PUT)
  339.                  menu=M_PUT;
  340.               m_selectmenu(menu);
  341.               dprintf(stderr," %d [%d]\n",menu,function);
  342.               }
  343.            break;
  344.         case '(':            /* swept area  */
  345.            {
  346.            int rx1,ry1,rx2,ry2;        /* rect coords */
  347.  
  348.            sscanf(line+1,"%d %d %d %d)",&rx1,&ry1,&rx2,&ry2);
  349.  
  350.            if (rx1>rx2) SWAP(rx1,rx2);
  351.            if (ry1>ry2) SWAP(ry1,ry2);
  352.  
  353.            rx1 = Max(rx1,x0);
  354.            ry1 = Max(ry1,y0);
  355.  
  356.            rx1 = (rx1-GAP)/x;
  357.            rx2 = (rx2-GAP)/x;
  358.            ry1 = (ry1-2*GAP-font_high)/y;
  359.            ry2 = (ry2-2*GAP-font_high)/y;
  360.  
  361.            rx2 = Min(rx2,W(map));
  362.            ry2 = Min(ry2,H(map));
  363.  
  364.            w = rx2 - rx1;
  365.            h = ry2 - ry1;
  366.            new = bit_create(map,rx1,ry1,w,h);
  367.            dprintf(stderr,"Extract %d,%d %dx%d code: %s\n",
  368.                            rx1,ry1,w,h,new?"YES":"NO");
  369.  
  370.            last = set_undo(last,map);
  371.  
  372.            if (function) {
  373.               INVERT(T_OP);
  374.               dprintf(stderr,"Doing function %d\n",function);
  375.               switch(function) {
  376.                  case YANK:
  377.                     if (yanked)
  378.                        bit_destroy(yanked);
  379.                     yanked = bit_alloc(W(new),H(new),BIT_NULL,1);
  380.                     bit_blit(yanked,0,0,
  381.                             W(new),H(new),BIT_SRC,new,0,0);
  382.                     dprintf(stderr,"yanked: %s\n",yanked?"YES":"NO");
  383.                     if (!yanked)
  384.                        message(SETMSG,"Can't yank bitmap");
  385.                     else
  386.                        message(SETMSG,sprintf(line,"Yanked bitmap %d x %d",
  387.                                W(new),H(new)));
  388.                     break;
  389.                  case PUT:
  390.                     if (!yanked) {
  391.                        message(SETMSG,"Nothing to PUT");
  392.                        break;
  393.                        }
  394.  
  395.                     w = Min(W(yanked),W(new));
  396.                     h = Min(H(yanked),H(new));
  397.  
  398.                     if (w<1 || h < 1) {
  399.                        message(SETMSG,"Put where??");
  400.                        break;
  401.                        }
  402.  
  403.                     /* setup and zoom bitmap */
  404.  
  405.                     temp = bit_alloc(w,h,BIT_NULL,1);
  406.                     bit_blit(temp,0,0,w,h,BIT_SRC,new,0,0);
  407.                     bit_blit(temp,0,0,w,h,func_zoom[put],yanked,0,0);
  408.                     zoom(temp,x0+rx1*x,y0+ry1*y,x,y,SET);
  409.                     bit_destroy(temp);
  410.  
  411.                     bit_blit(new,0,0,w,h,func_put[put],yanked,0,0);
  412.                     title[T_FUNC] = modes[mode].value;
  413.                     Do_title(title);
  414.                     dprintf(stderr,"put:%dx%d at %d,%d [%d]\n",
  415.                             w,h,rx1,ry1,put);
  416.                     break;
  417.                  case SHRINK:
  418.                     w = W(new);
  419.                     h = H(new);
  420.                     if (w<MIN || h<MIN) {
  421.                        message(SETMSG,"Icon would be too small");
  422.                        break;
  423.                        }
  424.                     temp = bit_alloc(w,h,BIT_NULL,1);
  425.                     bit_blit(temp,0,0,w,h,BIT_SRC,new,0,0);
  426.                     bit_destroy(new);
  427.                     bit_destroy(map);
  428.                     new = BIT_NULL;
  429.                     map = temp;
  430.                     get_scale(&x,&y,map);
  431.                     m_clear();
  432.                     zoom(map,x0,y0,x,y,SET);
  433.                     if (grid)
  434.                        draw_grid(map,x0,y0,x,y);
  435.                     title[T_SIZE] = sprintf(dims,"%d x %d",
  436.                             W(map),H(map));
  437.                     Do_title(title);
  438.                     break;
  439.                  case GROW:
  440.                     w = W(map)*W(map)/W(new);
  441.                     h = H(map)*H(map)/H(new);
  442.                     if (w>MAX || h>MAX) {
  443.                        message(SETMSG,"Icon would be too big");
  444.                        break;
  445.                        }
  446.                     temp = bit_alloc(w,h,BIT_NULL,1);
  447.                     fprintf(stderr,"growing to %d , %d\n",w,h);
  448.                     bit_blit(temp,0,0, w,h,BIT_CLR,0,0,0);
  449.                     bit_blit(temp,rx1,ry1,W(map),H(map),BIT_SRC,map,0,0);
  450.                     bit_destroy(new);
  451.                     bit_destroy(map);
  452.                     new = BIT_NULL;
  453.                     map = temp;
  454.                     get_scale(&x,&y,map);
  455.                     m_clear();
  456.                     zoom(map,x0,y0,x,y,SET);
  457.                     if (grid)
  458.                        draw_grid(map,x0,y0,x,y);
  459.                     title[T_SIZE] = sprintf(dims,"%d x %d",
  460.                             W(map),H(map));
  461.                     Do_title(title);
  462.                     break;
  463.                  case SHIFT:
  464.                     bit_blit(map,0,0,W(map),H(map)-1,BIT_SRC,map,0,1);
  465.                     zoom(map,x0,y0,x,y,SET);
  466.                     if (grid)
  467.                        draw_grid(map,x0,y0,x,y);
  468.                     break;
  469.                  }
  470.               function = 0;
  471.               }
  472.            else {
  473.               if (new && mode==TOGGLE) {
  474.                  bit_blit(new,0,0,W(new),H(new),
  475.                           BIT_NOT(BIT_DST),0,0,0);
  476.                  m_bitwrite(x0+rx1*x,y0+ry1*y,x*W(new),
  477.                             y*H(new));
  478.                  }
  479.               else if (new) {
  480.                  zoom(new,x0+rx1*x,y0+ry1*y,x,y,mode==SET?CLEAR:SET);
  481.                  bit_blit(new,0,0,W(new),H(new),
  482.                           mode==SET?BIT_SET:BIT_CLR,0,0,0);
  483.                  }
  484.               if (new)
  485.                  bit_destroy(new);
  486.               }
  487.            }
  488.            break;
  489.         case '$':            /* button up */
  490.            dprintf(stderr,"done\n");
  491.            menu = -1;
  492.            m_nomenu();
  493.            break;
  494.         case 's':            /* set bit mode */
  495.            c = *(line+1);
  496.            if (c>='0' && c<='2')
  497.               code = c - '0';
  498.            if (mode != code){
  499.               mode = code;
  500.               title[T_FUNC]=modes[mode].value;
  501.               Do_title(title);
  502.               }
  503.            break;
  504.         case '+':            /* specify bitmap size */
  505.            pntr=get_str("Enter new size (xxx,yyy):\n",
  506.                      mx,my,sizes,MENU_SIZE(sizes));
  507.            sscanf(pntr,"%d,%d",&w,&h);
  508.            if (w>MAX || h>MAX || w<MIN || h<MIN) {
  509.               message(SETMSG,"Sorry, invalid size");
  510.               break;
  511.               }
  512.            temp = bit_alloc(w,h,BIT_NULL,1);
  513.            fprintf(stderr,"resizing to %d , %d\n",w,h);
  514.            mx = w>W(map) ? (w - W(map))/2 : 0;
  515.            my = h>H(map) ? (h - H(map))/2 : 0;
  516.            bit_blit(temp,0,0,w,h,BIT_CLR,0,0,0);
  517.            bit_blit(temp,mx,my,W(map),H(map),BIT_SRC,map,0,0);
  518.            bit_destroy(map);
  519.            map = temp;
  520.            get_scale(&x,&y,map);
  521.            m_clear();
  522.            zoom(map,x0,y0,x,y,SET);
  523.            if (grid)
  524.               draw_grid(map,x0,y0,x,y);
  525.            title[T_SIZE] = sprintf(dims,"%d x %d",W(map),H(map));
  526.            Do_title(title);
  527.            if (function)
  528.               INVERT(T_OP);
  529.            break;
  530.         case 'f':            /* save file */
  531.            if ((pntr=get_str("Enter file name:\n",mx,my,files,file_count))
  532.                                   && *pntr) {
  533.               if (write_icon(pntr,map) && strcmp(name,pntr)!=0) {
  534.                  title[T_NAME] = strcpy(name,pntr);
  535.                  Do_title(title);
  536.                  if (function) INVERT(T_OP);
  537.               
  538.                  /* add new name to menu */
  539.  
  540.                  for(i=0;i<file_count;i++)
  541.                     if (strcmp(files[i].value,name)==0)
  542.                        break;
  543.                  if (i==file_count && file_count+1 < FILES) {
  544.                     files[file_count].value = str_save(name,"");
  545.                     files[file_count].action = str_save(name,"\r");
  546.                     file_count++;
  547.                     }
  548.                  }
  549.               }
  550.            else {
  551.               message(SETMSG,"No file saved");
  552.               }
  553.            break;
  554.         case 'g':            /* get file */
  555.            {
  556.            pntr = get_str("Enter file name:\n",mx,my,files,file_count);
  557.            if (pntr && *pntr && (new = read_icon(pntr,0))  != BIT_NULL) {
  558.               bit_destroy(map);
  559.               map=new;
  560.               m_clear();
  561.               code = get_scale(&x,&y,map);
  562.               zoom(map,x0,y0,x,y,SET);
  563.               title[T_SIZE] = sprintf(dims,"%d x %d",W(map),H(map));
  564.               title[T_NAME] = strcpy(name,pntr);
  565.               Do_title(title);
  566.               if (grid)
  567.                  draw_grid(map,x0,y0,x,y);
  568.               }
  569.            }
  570.            break;
  571.         case 'y':            /* yank file to buffer */
  572.            pntr = get_str("Enter file name:\n",mx,my,files,file_count);
  573.            if (pntr && *pntr && (new = read_icon(pntr,0))  != BIT_NULL) {
  574.               if (yanked)
  575.                  bit_destroy(yanked);
  576.               yanked = new;
  577.               new = BIT_NULL;
  578.               message(SETMSG,sprintf(line,"Yanked %s (%d x %d)",
  579.                       pntr,W(yanked),H(yanked)));
  580.               if (function == YANK) {
  581.                  INVERT(T_OP); 
  582.                  function = 0;
  583.                  }
  584.               }
  585.            else
  586.               message(SETMSG,"Can'y yank file");
  587.            break;
  588.         case 'w':            /* reshape window to icon size  */
  589.            code = Min(x,y);
  590.            m_shapewindow(win_x,win_y,W(map)*code+GAP+2*border,
  591.                         W(map)*code+2*font_high+GAP*3 + 2*border);
  592.            m_sendme("S\r");
  593.            break;
  594.         case 'P':            /* set put mode  */
  595.            code = *(line+1) - '0';
  596.            if (code<0 || code > 9)
  597.               code = 0;
  598.            if (put != code) {
  599.               put = code;
  600.               title[T_FUNC]=functions[put].value;
  601.               Do_title(title);
  602.               INVERT(T_OP);
  603.               }
  604.            break;
  605.         case 'F':            /* set option flags  */
  606.            code = *(line+1) - '0';
  607.  
  608.            if (code<0 || code > 9)
  609.               break;
  610.            if (code == PUT && !yanked)
  611.               break;
  612.  
  613.            if (code == function && function == PUT) {
  614.               function = 0;
  615.               title[T_FUNC] = modes[mode].value;
  616.               }
  617.            else if (code == function)
  618.               function = 0;
  619.            else {
  620.               function = code;
  621.               title[T_OP] = options[function-1].value;
  622.               dprintf(stderr,"setting function =  %d\n",code);
  623.               if (function == PUT)
  624.                  title[T_FUNC]=functions[put].value;
  625.               }
  626.            Do_title(title);
  627.            if (function)
  628.               INVERT(T_OP);
  629.            break;
  630.         case 'u':            /* undo */
  631.            if (!last)
  632.               break;
  633.  
  634.            /* get ready to undo the undo */
  635.  
  636.            temp = map;
  637.            map = last;
  638.            last = temp;
  639.  
  640.            /* make changes in situ */
  641.  
  642.            if (W(last)==W(map) && H(last)==H(map)) {
  643.               temp = bit_alloc(W(map),H(map),BIT_NULL,1);
  644.               bit_blit(temp,0,0,W(map),H(map),BIT_SRC,map,0,0);
  645.               bit_blit(temp,0,0,W(map),H(map),BIT_SRC^BIT_DST,last,0,0);
  646.               zoom(temp,x0,y0,x,y,SET);
  647.               bit_destroy(temp);
  648.               }
  649.  
  650.            /* redoit all */
  651.  
  652.            else {
  653.               get_scale(&x,&y,map);
  654.               m_clear();
  655.               zoom(map,x0,y0,x,y,SET);
  656.               if (grid)
  657.                  draw_grid(map,x0,y0,x,y);
  658.               title[T_SIZE] = sprintf(dims,"%d x %d", W(map),H(map));
  659.               Do_title(title);
  660.               }
  661.            break;
  662.         case 'M':            /* move */
  663.            get_size(&win_x,&win_y,0,0);
  664.            break;
  665.         case 'R':            /* redraw */
  666.            m_clear();
  667.            zoom(map,x0,y0,x,y,SET);
  668.            Do_title(title);
  669.            if (grid)
  670.               draw_grid(map,x0,y0,x,y);
  671.            if (function)
  672.               INVERT(T_OP);
  673.            break;
  674.         case 'S':            /* reshape */
  675.               {
  676.               int lastx = x;
  677.               int lasty = y;
  678.  
  679.               get_font(&font_wide, &font_high);
  680.               code = get_scale(&x,&y,map);
  681.               if (code>0 || lastx != x || lasty != y) {
  682.                  m_clear();
  683.                  zoom(map,x0,y0,x,y,SET);
  684.                  if (grid)
  685.                     draw_grid(map,x0,y0,x,y);
  686.                  }
  687.               Do_title(title);
  688.               if (function)
  689.                  INVERT(T_OP);
  690.               }
  691.               break;
  692.         case 'Q':            /* quit */
  693.            done++;
  694.            m_gets(line);        /* eat the "$" */
  695.            break;
  696.         case 'x':            /* toggle grid */
  697.            draw_grid(map,x0,y0,x,y);
  698.            grid = 1-grid;
  699.            break;
  700.         default:
  701.            break;
  702.         }
  703.      m_flush();
  704.      }
  705.    clean(0);
  706.    }
  707.  
  708. /* grid a bitmap onto the window */
  709.  
  710. int
  711. draw_grid(map,x,y,x_scale,y_scale)
  712. register BITMAP *map;        /* bitmap to zoom */
  713. int x,y;            /* screen location to start */
  714. int x_scale, y_scale;        /* scale factors (>1) */
  715.    {
  716.    register int sx,sy,dx,dy;    /* current src, dst coords */
  717.  
  718.    for(dy=y,sy=0;sy<H(map);sy++,dy+=y_scale)
  719.             m_bitwrite(x,dy,W(map)*x_scale,1);
  720.    for(dx=x,sx=0;sx<W(map);sx++,dx+=x_scale)
  721.             m_bitwrite(dx,y,1,H(map)*y_scale);
  722.    } 
  723.  
  724. /* zoom a bitmap onto the window */
  725.  
  726. #define X_ON(x)    (x != -1)
  727.  
  728. int
  729. zoom(map,x,y,x_scale,y_scale,how)
  730. register BITMAP *map;        /* bitmap to zoom */
  731. int x,y;            /* screen location to start */
  732. int x_scale, y_scale;        /* scale factors (>1) */
  733. int how;            /* 1==on bits  0==off bits */
  734.    {
  735.    register int sx,sy,dx,dy;    /* current src, dst coords */
  736.    int on, count=0, set_x;
  737.  
  738.    for(dy=y,sy=0;sy<H(map);sy++,dy+=y_scale) {
  739.       for(count=0,dx=x,sx=0;sx<W(map);sx++,dx+=x_scale) {
  740.          on = how==SET ? (bit_on(map,sx,sy)) : !(bit_on(map,sx,sy));
  741.          if (on && count)
  742.             count ++;
  743.          else if (on) {
  744.             count++;
  745.             set_x = dx;
  746.             }
  747.          else if (count) {
  748.             m_bitwrite(set_x,dy,count * x_scale,y_scale);
  749.             count = 0;
  750.             }
  751.          }
  752.       if (count)
  753.          m_bitwrite(set_x,dy,count * x_scale,y_scale);
  754.       }
  755.    } 
  756.  
  757.  
  758. int
  759. clean(n)
  760. int n;
  761.    {
  762.    m_moveprint(0,win_high,"done...");
  763.    m_popall();
  764.    m_ttyreset();
  765.    exit(n);
  766.    }
  767.  
  768. message(how,s)
  769. int how;
  770. char *s;
  771.    {
  772.    alarm(0);
  773.    if (how==SETMSG) {
  774.       m_moveprint(0,win_high,s);
  775.       m_flush();
  776.       dprintf(stderr,"Setting message [%s]\n",s);
  777.       alarm(SLEEP);
  778.       }
  779.    else {
  780.       m_movecursor(0,win_high);
  781.       dprintf(stderr,"clearing message\n");
  782.       }
  783.    m_cleareol();
  784.    m_movecursor(win_wide,win_high);
  785.    m_flush();
  786.    }
  787.  
  788. int Do_title(args)
  789. char **args;
  790.    {
  791.    register int i, count;
  792.    int len[MAXMARK];        /* label sizes */
  793.    int sum;            /* total label width */
  794.    int x = 0;            /* starting label position */
  795.    int y = font_high;        /* starting label position */
  796.    register char **label=args;
  797.  
  798.    SET_FUNC(B_SET);
  799.    m_movecursor(0,y);
  800.    m_cleareol();
  801.  
  802.    for(sum=count=0;*label;count++,label++)
  803.       sum += (len[count] = strlen(*label) * font_wide + GAP);
  804.    for(i=0;i<count;i++) {
  805.       marks[i] = MARK(i-1) + len[i] * win_wide / sum;
  806.       if (i+1 == count)
  807.          marks[i] = win_wide;        /* fix rounding error */
  808.       dprintf(stderr,"%s (%d)at %d=>%d ",
  809.               args[i],len[i],MARK(i-1),MARK(i));
  810.       if (MARK(i) - MARK(i-1) > len[i])
  811.          m_moveprint((MARK(i)+MARK(i-1)- len[i])/2,y,args[i]);
  812.       m_bitwrite(marks[i],0,GAP,y);
  813.       }
  814.    dprintf(stderr,"(%d)\n",win_wide);
  815.  
  816.    m_bitwrite(0,y,win_wide,GAP);
  817.    m_movecursor(win_wide+font_wide,y);
  818.    SET_FUNC(B_INVERT);
  819.    
  820.    return(count);
  821.    }
  822.  
  823. /* get a user string */
  824.  
  825.  
  826. char *
  827. get_str(s,x,y,menu,count)
  828. char *s;            /* text to display */
  829. int x,y;            /* center of window */
  830. struct menu_entry *menu;    /* menu to down load */
  831. int count;            /* # of menu items */
  832.    {
  833.    static char input[128];
  834.    int wide = Max(15,strlen(s)) * font_wide + 2*border;
  835.    int high = 2*(font_high + border);
  836.    int x0 = win_x + x - wide/2;
  837.    int y0 = win_y + y + font_high;
  838.    int win;
  839.    char *pntr, *index();
  840.  
  841.    if (x0<0)
  842.       x0 = GAP;
  843.    if (x0+wide > xmax)
  844.       x0 = xmax-wide-GAP;
  845.    if (y0+high > ymax)
  846.       y0 = ymax-high-GAP;
  847.  
  848.    dprintf(stderr,"Making %d,%d %dx%d\n",x0,y0,wide,high);
  849.    message(SIGALRM);        /* turn of any pending message */
  850.  
  851.    m_newwin(x0,y0,wide,high);
  852.    m_flush();
  853.    m_gets(input);
  854.    if (*input == '$') {        /* button already let go */
  855.       dprintf(stderr,"$ in makewin\n");
  856.       m_gets(input);
  857.       }
  858.  
  859.    dprintf(stderr,"makewin returns %s",input);
  860.    win = atoi(input);
  861.    dprintf(stderr,"Created %d\n",win);
  862.  
  863.    *input = '\0';
  864.    if (win) {
  865.       m_selectwin(win);
  866.       m_setevent(DEACTIVATED,"\r");
  867.       m_setevent(DESTROY,"\r");
  868.       m_setevent(RESHAPE,"\r");
  869.       m_setevent(BUTTON_1,"%n\r");
  870.       m_setevent(ACCEPT,"%m\r");
  871.       if (count > 0) {
  872.          menu_load(1,count,menu);
  873.          m_selectmenu(1);
  874.          }
  875.       m_printstr(s);
  876.       dprintf(stderr,"prompt: %s ...",s);
  877.       fflush(stderr);
  878.       m_flush();
  879.       m_ttyreset();
  880.       m_gets(input);
  881.  
  882.       pntr = input;
  883.       if (pntr=index(input,' '))
  884.          *pntr='\0';
  885.       if (pntr=index(input,'\n'))
  886.          *pntr='\0';
  887.  
  888.       m_ttyset();
  889.       dprintf(stderr,"Got: %s\n",input); fflush(stderr);
  890.       m_selectwin(0);
  891.       m_destroywin(win);
  892.       m_flush();
  893.       } 
  894.    else
  895.       message(SETMSG,"Sorry, Can't make prompt window");
  896.    return(input);
  897.    }
  898.  
  899. /* read in icon */ 
  900.  
  901. BITMAP *
  902. read_icon(name)
  903. char *name;                /* name of icon file */
  904.    {
  905.    FILE *fp;                /* fp to read bitmap from */
  906.    BITMAP *map, *bitmapread();
  907.    char tmp[100];
  908.  
  909.    if ((fp = fopen(name,"r")) == NULL ) {
  910.       message(SETMSG,sprintf(tmp,"Can't find %s",name));
  911.       return(BIT_NULL);
  912.       }
  913.  
  914.    if( !( map = bitmapread(fp) ) ) {
  915.       fclose(fp);
  916.       message(SETMSG,sprintf(tmp,"%s is not an icon or is damaged",name));
  917.       return(BIT_NULL);
  918.       }
  919.  
  920.    fclose(fp);
  921.    return(map);
  922.    }
  923.  
  924. int
  925. get_scale(x,y,map)
  926. register int *x, *y;
  927. BITMAP *map;
  928.    {
  929.    char line[256];
  930.    int w = W(map);
  931.    int h = H(map);
  932.    int count;
  933.  
  934.    for(count=0;;count++) {
  935.       get_size(&win_x,&win_y,&win_wide,&win_high);
  936.       *x = (win_wide - x0)/w;
  937.       *y = (win_high - y0 - font_high)/h;
  938.       if (*x>=1 && *y>=1) 
  939.          break;
  940.       m_clear();
  941.       m_clearmode(M_NOWRAP);
  942.       m_printstr("Window is too small\n");
  943.       m_gets(line); 
  944.       }
  945.    if (count)
  946.       m_setmode(M_NOWRAP);
  947.    return(count);
  948.    }
  949.  
  950.  
  951. int
  952. write_icon(name,map)
  953. char *name;
  954. BITMAP *map;
  955.    {
  956.    FILE *fp = fopen(name,"w");
  957.    char tmp[100];
  958.  
  959.    if (fp == NULL  ||  !bitmapwrite(fp,map)) {
  960.       dprintf(stderr,"Can't write file %s\n",name);
  961.       message(SETMSG,sprintf(tmp,"Can't write file %s",name));
  962.       return(0);
  963.       }
  964.    fclose(fp);
  965.    return(1);
  966.    }
  967.  
  968. /* do mode to bit, fix up display */
  969.  
  970. int
  971. do_bit(map,x,y,bitx,bity,mode)
  972. BITMAP *map;
  973. int x,y;        /* scale factors */
  974. int bitx,bity;        /* bit to do */
  975. int mode;        /* SET, CLEAR, or TOGGLE */
  976.    {
  977.    int state = bit_on(map,bitx,bity) ? ON : OFF;
  978.    switch(mode | state) {
  979.       case TOGGLE | OFF:
  980.       case TOGGLE | ON:
  981.       case SET | OFF:
  982.       case CLEAR | ON:
  983.          bit_point(map,bitx,bity,BIT_NOT(BIT_DST));
  984.          m_bitwrite(x0+bitx*x,y0+bity*y,x,y);
  985.          dprintf(stderr,"toggle (%d)\n",mode|state);
  986.          break;
  987.       }
  988.    }
  989.  
  990. /* save map for undo */
  991.  
  992. BITMAP *
  993. set_undo(last,map)
  994. BITMAP *last, *map;
  995.    {
  996.    if (!last)
  997.       last = bit_alloc(W(map),H(map),BIT_NULL,1);
  998.    else if (W(last)!=W(map) || H(last)!=H(map)) {
  999.       bit_destroy(last);
  1000.       last = bit_alloc(W(map),H(map),BIT_NULL,1);
  1001.       }
  1002.    bit_blit(last,0,0,W(last),H(last),BIT_SRC,map,0,0);
  1003.    return(last);
  1004.    }
  1005.  
  1006. /* alloc and save space for the concatenation of s1 and s2 */
  1007.  
  1008. char *str_save(s1,s2)
  1009. char *s1, *s2;
  1010.    {
  1011.    char *malloc();
  1012.    char *result;
  1013.  
  1014.    if ((result = malloc(strlen(s1) + strlen(s2) + 1)) == NULL) {
  1015.       fprintf(stderr,"Malloc failed\n");
  1016.       clean(1);  
  1017.       }
  1018.  
  1019.    strcpy(result,s1);
  1020.    strcat(result,s2);
  1021.    return(result);
  1022.    }
  1023.